package br.ufmg.ubicomp.droidguide.communication;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;


import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

import br.ufmg.ubicomp.droidguide.common.DroidGuideConfigurationManager;
import br.ufmg.ubicomp.droidguide.common.EntityProperties;
import br.ufmg.ubicomp.droidguide.eventservice.DroidGuideRemoteService;
import br.ufmg.ubicomp.droidguide.eventservice.enums.ServiceType;
import br.ufmg.ubicomp.droidguide.eventservice.service.ServiceSubscription;
import br.ufmg.ubicomp.droidguide.utils.DateUtil;
import br.ufmg.ubicomp.droidguide.utils.RequestUtil;

public class ServiceCommunicationService extends CommunicationService{

	public static final String BASE_URL = DroidGuideConfigurationManager.getInstance().getData("server")+ 
		"service/process?operation=";

	/**
	 * lists all services in the system
	 * @return list of services.
	 * @throws Exception
	 */
	public static Collection<DroidGuideRemoteService> getListOfServices() throws Exception {
		String url = BASE_URL + "list";

		NodeList entities = RequestUtil.executeUrlDOM(url); 
			//processRequest(url);

		return getListOfServicesFromResult(entities);
	}

	private static Collection<DroidGuideRemoteService> getListOfServicesFromResult(
			NodeList entities) {
		
		Collection<DroidGuideRemoteService> services = new ArrayList<DroidGuideRemoteService>();

		for (int i = 0; i < entities.getLength(); i++) {
			Node entityEntry = entities.item(i);

			if (entityEntry instanceof Element) {
				Element entityElement = (Element) entityEntry;

				if (entityElement.getAttribute("kind").equals("Service")) {
					DroidGuideRemoteService service = getServiceObject(entityElement);
					services.add(service);
				}
			}
		}

		return services;
	}

	protected static DroidGuideRemoteService getServiceObject(Element entityElement) {
		DroidGuideRemoteService service = new DroidGuideRemoteService();
		service.setKey(entityElement.getAttribute("key"));
	
		NodeList properties = entityElement.getChildNodes();
	
		for (int j = 0; j < properties.getLength(); j++) {
			Node propertyEntry = properties.item(j);
	
			if (propertyEntry instanceof Element) {
				Element propertyElement = (Element) propertyEntry;
	
				Text textNode = (Text) propertyElement
						.getFirstChild();
				String text = textNode.getData().trim();
	
				if (propertyElement.getTagName().equals("property")) {
					String attributeName = propertyElement
							.getAttribute("name");
					if (attributeName.equals("description")) {
						service.setDescription(text);
					} else if (attributeName.equals("type")) {
						if (text.equals("weather")) {
							service.addType(ServiceType.WEATHER);
						} else if (text.equals("tourism")) {
							service.addType(ServiceType.TOURISM);
						} else if (text.equals("traffic")) {
							service.addType(ServiceType.TRAFFIC);
						} else if (text.equals("location")) {
							service.addType(ServiceType.LOCATION);
						} else if (text.equals("business")) {
							service.addType(ServiceType.BUSINESS);
						} else if (text.equals("emergency")) {
							service.addType(ServiceType.EMERGENCY);
						} else if (text.equals("shopping")) {
							service.addType(ServiceType.SHOPPING);
						}
					} else if (attributeName.equals("data")) {
						service.setData(text);
					} else if (attributeName.equals("state")) {
						service.setState(text);
					}
				}
			}
		}
		return service;
	}

	/**
	 * subscribes one user to a service in the system.
	 * @param serviceKey
	 * @param droidGuideUserKey
	 * @return
	 * @throws Exception
	 */
	public static Collection<ServiceSubscription> subscribeToService(String serviceKey,
			String droidGuideUserKey) throws Exception {
		String url = BASE_URL + "subscribe&service_key=" + serviceKey
				+ "&droidGuideUser_key=" + droidGuideUserKey;

		NodeList entities = RequestUtil.executeUrlDOM(url); 
			//processRequest(url);

		Collection<ServiceSubscription> userToServices = new ArrayList<ServiceSubscription>();
		
		for (int i = 0; i < entities.getLength(); i++) {
			Node entityEntry = entities.item(i);

			if (entityEntry instanceof Element) {
				Element entityElement = (Element) entityEntry;

				if (entityElement.getAttribute("kind").equals("UserToService")) {

					ServiceSubscription userToService = getUserToServiceObject(entityElement);
					userToServices.add(userToService);
				}
			}
		}

		return userToServices;

	}

	private static ServiceSubscription getUserToServiceObject(Element entityElement) throws ParseException {
		ServiceSubscription userToService = new ServiceSubscription();

		NodeList properties = entityElement.getChildNodes();

		for (int j = 0; j < properties.getLength(); j++) {
			Node propertyEntry = properties.item(j);

			if (propertyEntry instanceof Element) {
				Element propertyElement = (Element) propertyEntry;

				Text textNode = (Text) propertyElement
						.getFirstChild();
				String text = textNode.getData().trim();

				if (propertyElement.getTagName().equals("property")) {
					String attributeName = propertyElement
							.getAttribute("name");

					if (attributeName.equals("droidGuideUser_key")) {
						userToService.setDroidGuideUserKey(text);
					} else if (attributeName.equals("service_key")) {
						userToService.setServiceKey(text);
					} else if (attributeName.equals("datatime")) {
						// TODO: parse date received.
						Calendar c = DateUtil.parseXmlDateTime(text);
						userToService.setDateTime(c);
						// 2008-11-20 16:20:29.210330
						// userToService.setDateTime();
					}
				}
			}
		}
		return userToService;
	}

	/**
	 * unsubscribes an user to a service
	 * @param serviceKey
	 * @param droidGuideUserKey
	 * @return
	 * @throws Exception
	 */
	public static Collection<ServiceSubscription> unsubscribeToService(String serviceKey,
			String droidGuideUserKey) throws Exception {
		String url = BASE_URL + "unsubscribe&service_key=" + serviceKey
				+ "&droidGuideUser_key=" + droidGuideUserKey;

		NodeList entities = RequestUtil.executeUrlDOM(url); 
			//processRequest(url);

		Collection<ServiceSubscription> userToServices = new ArrayList<ServiceSubscription>();

		for (int i = 0; i < entities.getLength(); i++) {
			Node entityEntry = entities.item(i);

			if (entityEntry instanceof Element) {
				Element entityElement = (Element) entityEntry;

				if (entityElement.getAttribute("kind").equals("UserToService")) {
					ServiceSubscription userToService = getUserToServiceObject(entityElement);
					userToServices.add(userToService);
				}
			}
		}

		return userToServices;

	}

	/**
	 * gets the list of subscribed services
	 * @param droidGuideUserKey
	 * @return
	 * @throws Exception
	 */
	public static Collection<DroidGuideRemoteService> getSubscribedServices(String droidGuideUserKey) throws Exception {
		String url = BASE_URL + "listSubscribed&droidGuideUser_key=" + droidGuideUserKey;

		NodeList entities = RequestUtil.executeUrlDOM(url); 
			//processRequest(url);
		
		return getListOfServicesFromResult(entities);

	}

}
